using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Windows.Forms;
using Microsoft.WowAddonStudio.FrameXml.Components.Support;
using Microsoft.WowAddonStudio.FrameXml.Serialization.LayoutFrames;
using Color=System.Drawing.Color;

namespace Microsoft.WowAddonStudio.FrameXml.Components
{
    public partial class UiControl
    {
        /// <summary>
        /// Paints the control.
        /// </summary>
        /// <param name="e">The <see cref="FrameXmlPaintEventArgs"/> containing the event data.</param>
        protected override void OnPaint(FrameXmlPaintEventArgs e)
        {
            base.OnPaint(e);

            // Paint the frames
            this.PaintUi(e);
        }

		/// <summary>
		/// Paints the UI.
		/// </summary>
		/// <param name="e">The <see cref="Microsoft.WowAddonStudio.FrameXml.Components.Support.FrameXmlPaintEventArgs"/> instance containing the event data.</param>
        private void PaintUi(FrameXmlPaintEventArgs e)
        {
            // Get the frame controls
			var frameControls = this.GetChildControls<FrameControl>().Where(frameControl => !frameControl.IsHidden);

            // Paint the frame controls
            this.PaintFrames(e, frameControls);
            
            // Get the virtual controls
		    var virtualControls = this.GetChildControls<LayoutFrameControl>().Where(layoutFrameControl => layoutFrameControl.LayoutFrame.Virtual && !layoutFrameControl.IsHidden);

            // Paint the virtual controls
		    this.PaintControls(e, virtualControls);
        }

		/// <summary>
		/// Paints the frames.
		/// </summary>
		/// <param name="e">The <see cref="Microsoft.WowAddonStudio.FrameXml.Components.Support.FrameXmlPaintEventArgs"/> instance containing the event data.</param>
		/// <param name="frameControls">The frame controls.</param>
        private void PaintFrames(FrameXmlPaintEventArgs e, IEnumerable<FrameControl> frameControls)
        {
            // Group the frames by framestrata and sort them
            var groupedFrameControls = frameControls.GroupBy(frameControl => frameControl.Frame.GetFrameStrata())
                                                    .OrderBy(group => group.Key);

            // Iterate through the framestrata groups
            foreach (var frameControlGroup in groupedFrameControls)
            {
                // Paint the FrameStrata
                this.PaintFrameStrata(e, frameControlGroup);
            }
        }

		/// <summary>
		/// Paints the frame strata.
		/// </summary>
		/// <param name="e">The <see cref="Microsoft.WowAddonStudio.FrameXml.Components.Support.FrameXmlPaintEventArgs"/> instance containing the event data.</param>
		/// <param name="frameControls">The frame controls.</param>
        private void PaintFrameStrata(FrameXmlPaintEventArgs e, IEnumerable<FrameControl> frameControls)
        {
            foreach (var frameControl in frameControls)
            {
                // Paint the frame
                this.PaintFrameXmlControl(e, frameControl);

                // Get the textures and fontstrings, group and order them by layer
                var textureControls = frameControl.GetChildControls<TextureControl>().Where(textureControl => !textureControl.IsHidden);
                var fontStringControls = frameControl.GetChildControls<FontStringControl>().Where(fontStringControl => !fontStringControl.IsHidden);

                var groupedLayerControls = textureControls.Cast<LayoutFrameControl>().Concat(fontStringControls.Cast<LayoutFrameControl>())
                                                                                     .GroupBy(layoutFrameControl => ((LayeredLayoutFrame)layoutFrameControl.LayoutFrame).DrawLayer)
                                                                                     .OrderBy(group => group.Key);

                foreach (var group in groupedLayerControls)
                {
                    // Iterate through each control in the group and paint it
                    foreach (var control in group)
                        this.PaintFrameXmlControl(e, control);
                }
            }
        }

        private void PaintControls(FrameXmlPaintEventArgs e, IEnumerable<LayoutFrameControl> controls)
        {
            foreach (var control in controls)
                this.PaintFrameXmlControl(e, control);
        }

		/// <summary>
		/// Paints the frame XML control.
		/// </summary>
		/// <param name="e">The <see cref="Microsoft.WowAddonStudio.FrameXml.Components.Support.FrameXmlPaintEventArgs"/> instance containing the event data.</param>
		/// <param name="control">The control.</param>
        private void PaintFrameXmlControl(FrameXmlPaintEventArgs e, IFrameXmlControl control)
        {
            try
            {
                if (control.DrawControl(e.FrameXmlGraphics, new Rectangle(GetControlLocation(control), control.Size)))
                    return;
            }
            catch (FrameXmlGraphicsException)
            {
            }

            control.DrawPlaceholder(e.FrameXmlGraphics, new Rectangle(GetControlLocation(control), control.Size));
        }

		/// <summary>
		/// Gets the control location.
		/// </summary>
		/// <param name="control">The control.</param>
		/// <returns></returns>
        private Point GetControlLocation(IFrameXmlControl control)
        {
            return this.PointToClient(control.Parent.PointToScreen(control.Location));
        }

		/// <summary>
		/// Initializes the background.
		/// </summary>
		private void InitializeBackground(string backgroundImagePath)
		{
            if (File.Exists(backgroundImagePath))
            {
                try
                {
                    this.BackgroundImage = Image.FromFile(backgroundImagePath);
                    this.BackgroundImageLayout = ImageLayout.Center;
                }
                catch (FileNotFoundException)
                {
                }
                catch (OutOfMemoryException)
                {
                }
                catch (Exception ex)
                {
                    Trace.WriteLine(ex);
                }
            }
            else
            {
                this.BackgroundImage = Resources.DefaultBackground;
                this.BackgroundImageLayout = ImageLayout.None;
            }
		}
    }
}
